package util

import "sync"

type JumpConsumer struct {
	cond     *sync.Cond
	bfSize   int
	message  []any
	writeIdx int
	count    int
}

func NewJumpConsumer(bufferSize int) *JumpConsumer {
	return &JumpConsumer{
		message: make([]any, 720),
		cond:    sync.NewCond(&sync.Mutex{}),
		bfSize:  bufferSize,
	}
}

func (jc *JumpConsumer) Push(mess any) {
	jc.cond.L.Lock()
	defer jc.cond.L.Unlock()

	// 数据满了之后几乎count就是满的，除非消费之后整体清空。此处先减后加
	if jc.count == jc.bfSize {
		jc.count--
	}

	jc.message[jc.writeIdx] = mess
	jc.writeIdx = (jc.writeIdx + 1) % jc.bfSize
	jc.count++

	jc.cond.Signal()
}

func (jc *JumpConsumer) Poll() any {
	jc.cond.L.Lock()
	defer jc.cond.L.Unlock()

	// 避免cpu消耗过高，协程进入挂起等待
	if jc.count == 0 {
		jc.cond.Wait()
	}

	// 默认加一个bfSize，避免初始writeIdx为0时越界
	index := (jc.writeIdx - 1 + jc.bfSize) % jc.bfSize
	mess := jc.message[index]

	// 获取完最新值 直接清空，因为加锁，此时生产者不会写，因此不会导致数据丢失。
	jc.count = 0
	jc.writeIdx = 0

	return mess
}
